// 工具函数库

import { DATE_FORMATS } from '@/constants';

/**
 * 格式化日期
 * @param date 日期
 * @param format 格式
 * @returns 格式化后的日期字符串
 */
export const formatDate = (date: string | Date, format: string = DATE_FORMATS.DATETIME): string => {
  const d = new Date(date);
  
  if (isNaN(d.getTime())) {
    return '';
  }

  const year = d.getFullYear();
  const month = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  const hours = String(d.getHours()).padStart(2, '0');
  const minutes = String(d.getMinutes()).padStart(2, '0');
  const seconds = String(d.getSeconds()).padStart(2, '0');

  return format
    .replace('YYYY', String(year))
    .replace('MM', month)
    .replace('DD', day)
    .replace('HH', hours)
    .replace('mm', minutes)
    .replace('ss', seconds);
};

/**
 * 获取相对时间描述
 * @param date 日期
 * @returns 相对时间描述
 */
export const getRelativeTime = (date: string | Date): string => {
  const now = new Date();
  const target = new Date(date);
  const diff = now.getTime() - target.getTime();

  const minute = 60 * 1000;
  const hour = 60 * minute;
  const day = 24 * hour;
  const week = 7 * day;
  const month = 30 * day;
  const year = 365 * day;

  if (diff < minute) {
    return '刚刚';
  } else if (diff < hour) {
    return `${Math.floor(diff / minute)}分钟前`;
  } else if (diff < day) {
    return `${Math.floor(diff / hour)}小时前`;
  } else if (diff < week) {
    return `${Math.floor(diff / day)}天前`;
  } else if (diff < month) {
    return `${Math.floor(diff / week)}周前`;
  } else if (diff < year) {
    return `${Math.floor(diff / month)}个月前`;
  } else {
    return `${Math.floor(diff / year)}年前`;
  }
};

/**
 * 格式化金额
 * @param amount 金额
 * @param currency 货币符号
 * @returns 格式化后的金额字符串
 */
export const formatCurrency = (amount: number, currency: string = '¥'): string => {
  return `${currency}${amount.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
};

/**
 * 格式化文件大小
 * @param bytes 字节数
 * @returns 格式化后的文件大小
 */
export const formatFileSize = (bytes: number): string => {
  if (bytes === 0) return '0 B';

  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));

  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
};

/**
 * 生成唯一ID
 * @returns 唯一ID字符串
 */
export const generateId = (): string => {
  return Date.now().toString(36) + Math.random().toString(36).substr(2);
};

/**
 * 防抖函数
 * @param func 要防抖的函数
 * @param wait 等待时间
 * @returns 防抖后的函数
 */
export const debounce = <T extends (...args: unknown[]) => unknown>(
  func: T,
  wait: number
): ((...args: Parameters<T>) => void) => {
  let timeout: NodeJS.Timeout;
  
  return (...args: Parameters<T>) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => func(...args), wait);
  };
};

/**
 * 节流函数
 * @param func 要节流的函数
 * @param limit 限制时间
 * @returns 节流后的函数
 */
export const throttle = <T extends (...args: unknown[]) => unknown>(
  func: T,
  limit: number
): ((...args: Parameters<T>) => void) => {
  let inThrottle: boolean;
  
  return (...args: Parameters<T>) => {
    if (!inThrottle) {
      func(...args);
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
    }
  };
};

/**
 * 深拷贝对象
 * @param obj 要拷贝的对象
 * @returns 拷贝后的对象
 */
export const deepClone = <T>(obj: T): T => {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  if (obj instanceof Date) {
    return new Date(obj.getTime()) as T;
  }

  if (obj instanceof Array) {
    return obj.map(item => deepClone(item)) as T;
  }

  if (typeof obj === 'object') {
    const clonedObj = {} as T;
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        clonedObj[key] = deepClone(obj[key]);
      }
    }
    return clonedObj;
  }

  return obj;
};

/**
 * 检查对象是否为空
 * @param obj 要检查的对象
 * @returns 是否为空
 */
export const isEmpty = (obj: unknown): boolean => {
  if (obj === null || obj === undefined) return true;
  if (typeof obj === 'string') return obj.trim() === '';
  if (Array.isArray(obj)) return obj.length === 0;
  if (typeof obj === 'object') return Object.keys(obj).length === 0;
  return false;
};

/**
 * 获取对象指定路径的值
 * @param obj 对象
 * @param path 路径，如 'a.b.c'
 * @param defaultValue 默认值
 * @returns 值
 */
export const get = (obj: Record<string, unknown>, path: string, defaultValue?: unknown): unknown => {
  const keys = path.split('.');
  let result = obj;

  for (const key of keys) {
    if (result && typeof result === 'object' && key in result) {
      result = result[key] as Record<string, unknown>;
    } else {
      return defaultValue;
    }
  }

  return result;
};

/**
 * 设置对象指定路径的值
 * @param obj 对象
 * @param path 路径，如 'a.b.c'
 * @param value 值
 */
export const set = (obj: Record<string, unknown>, path: string, value: unknown): void => {
  const keys = path.split('.');
  let current = obj;

  for (let i = 0; i < keys.length - 1; i++) {
    const key = keys[i];
    if (!(key in current) || typeof current[key] !== 'object') {
      current[key] = {};
    }
    current = current[key] as Record<string, unknown>;
  }

  current[keys[keys.length - 1]] = value;
};

/**
 * 数组去重
 * @param arr 数组
 * @param key 去重的键名（对象数组时使用）
 * @returns 去重后的数组
 */
export const unique = <T>(arr: T[], key?: keyof T): T[] => {
  if (!key) {
    return [...new Set(arr)];
  }

  const seen = new Set();
  return arr.filter(item => {
    const value = item[key];
    if (seen.has(value)) {
      return false;
    }
    seen.add(value);
    return true;
  });
};

/**
 * 数组分组
 * @param arr 数组
 * @param key 分组的键名
 * @returns 分组后的对象
 */
export const groupBy = <T>(arr: T[], key: keyof T): Record<string, T[]> => {
  return arr.reduce((groups, item) => {
    const groupKey = String(item[key]);
    if (!groups[groupKey]) {
      groups[groupKey] = [];
    }
    groups[groupKey].push(item);
    return groups;
  }, {} as Record<string, T[]>);
};

/**
 * 数组排序
 * @param arr 数组
 * @param key 排序的键名
 * @param order 排序方向
 * @returns 排序后的数组
 */
export const sortBy = <T>(arr: T[], key: keyof T, order: 'asc' | 'desc' = 'asc'): T[] => {
  return [...arr].sort((a, b) => {
    const aVal = a[key];
    const bVal = b[key];

    if (aVal < bVal) return order === 'asc' ? -1 : 1;
    if (aVal > bVal) return order === 'asc' ? 1 : -1;
    return 0;
  });
};

/**
 * 本地存储工具
 */
export const storage = {
  /**
   * 获取本地存储值
   * @param key 键名
   * @param defaultValue 默认值
   * @returns 值
   */
  get: <T>(key: string, defaultValue?: T): T | null => {
    if (typeof window === 'undefined') return defaultValue || null;
    
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : defaultValue || null;
    } catch {
      return defaultValue || null;
    }
  },

  /**
   * 设置本地存储值
   * @param key 键名
   * @param value 值
   */
  set: (key: string, value: unknown): void => {
    if (typeof window === 'undefined') return;
    
    try {
      localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error('Failed to set localStorage:', error);
    }
  },

  /**
   * 删除本地存储值
   * @param key 键名
   */
  remove: (key: string): void => {
    if (typeof window === 'undefined') return;
    localStorage.removeItem(key);
  },

  /**
   * 清空本地存储
   */
  clear: (): void => {
    if (typeof window === 'undefined') return;
    localStorage.clear();
  },
};

/**
 * URL 工具
 */
export const url = {
  /**
   * 获取 URL 参数
   * @param name 参数名
   * @param url URL 字符串
   * @returns 参数值
   */
  getParam: (name: string, url?: string): string | null => {
    if (typeof window === 'undefined') return null;
    
    const targetUrl = url || window.location.href;
    const urlObj = new URL(targetUrl);
    return urlObj.searchParams.get(name);
  },

  /**
   * 设置 URL 参数
   * @param params 参数对象
   * @param url URL 字符串
   * @returns 新的 URL 字符串
   */
  setParams: (params: Record<string, string>, url?: string): string => {
    if (typeof window === 'undefined') return '';
    
    const targetUrl = url || window.location.href;
    const urlObj = new URL(targetUrl);
    
    Object.entries(params).forEach(([key, value]) => {
      urlObj.searchParams.set(key, value);
    });
    
    return urlObj.toString();
  },

  /**
   * 删除 URL 参数
   * @param names 参数名数组
   * @param url URL 字符串
   * @returns 新的 URL 字符串
   */
  removeParams: (names: string[], url?: string): string => {
    if (typeof window === 'undefined') return '';
    
    const targetUrl = url || window.location.href;
    const urlObj = new URL(targetUrl);
    
    names.forEach(name => {
      urlObj.searchParams.delete(name);
    });
    
    return urlObj.toString();
  },
};

/**
 * 验证工具
 */
export const validate = {
  /**
   * 验证邮箱
   * @param email 邮箱地址
   * @returns 是否有效
   */
  email: (email: string): boolean => {
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return regex.test(email);
  },

  /**
   * 验证手机号
   * @param phone 手机号
   * @returns 是否有效
   */
  phone: (phone: string): boolean => {
    const regex = /^1[3-9]\d{9}$/;
    return regex.test(phone);
  },

  /**
   * 验证身份证号
   * @param idCard 身份证号
   * @returns 是否有效
   */
  idCard: (idCard: string): boolean => {
    const regex = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
    return regex.test(idCard);
  },

  /**
   * 验证密码强度
   * @param password 密码
   * @returns 强度等级 (1-4)
   */
  passwordStrength: (password: string): number => {
    let strength = 0;
    
    if (password.length >= 8) strength++;
    if (/[a-z]/.test(password)) strength++;
    if (/[A-Z]/.test(password)) strength++;
    if (/[0-9]/.test(password)) strength++;
    if (/[^A-Za-z0-9]/.test(password)) strength++;
    
    return Math.min(strength, 4);
  },
};

/**
 * 文件工具
 */
export const file = {
  /**
   * 下载文件
   * @param url 文件 URL
   * @param filename 文件名
   */
  download: (url: string, filename?: string): void => {
    const link = document.createElement('a');
    link.href = url;
    link.download = filename || '';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  },

  /**
   * 读取文件内容
   * @param file 文件对象
   * @returns Promise<string>
   */
  readAsText: (file: File): Promise<string> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result as string);
      reader.onerror = reject;
      reader.readAsText(file);
    });
  },

  /**
   * 读取文件为 Base64
   * @param file 文件对象
   * @returns Promise<string>
   */
  readAsDataURL: (file: File): Promise<string> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result as string);
      reader.onerror = reject;
      reader.readAsDataURL(file);
    });
  },

  /**
   * 获取文件扩展名
   * @param filename 文件名
   * @returns 扩展名
   */
  getExtension: (filename: string): string => {
    return filename.split('.').pop()?.toLowerCase() || '';
  },

  /**
   * 检查文件类型
   * @param file 文件对象
   * @param allowedTypes 允许的类型数组
   * @returns 是否允许
   */
  checkType: (file: File, allowedTypes: string[]): boolean => {
    const extension = file.name.split('.').pop()?.toLowerCase();
    return allowedTypes.includes(extension || '');
  },

  /**
   * 检查文件大小
   * @param file 文件对象
   * @param maxSize 最大大小（字节）
   * @returns 是否符合要求
   */
  checkSize: (file: File, maxSize: number): boolean => {
    return file.size <= maxSize;
  },
};

/**
 * 颜色工具
 */
export const color = {
  /**
   * 十六进制转 RGB
   * @param hex 十六进制颜色
   * @returns RGB 对象
   */
  hexToRgb: (hex: string): { r: number; g: number; b: number } | null => {
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
      r: parseInt(result[1], 16),
      g: parseInt(result[2], 16),
      b: parseInt(result[3], 16)
    } : null;
  },

  /**
   * RGB 转十六进制
   * @param r 红色值
   * @param g 绿色值
   * @param b 蓝色值
   * @returns 十六进制颜色
   */
  rgbToHex: (r: number, g: number, b: number): string => {
    return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
  },

  /**
   * 生成随机颜色
   * @returns 随机十六进制颜色
   */
  random: (): string => {
    return `#${Math.floor(Math.random() * 16777215).toString(16)}`;
  },
};

/**
 * 导出所有工具函数
 */
export default {
  formatDate,
  getRelativeTime,
  formatCurrency,
  formatFileSize,
  generateId,
  debounce,
  throttle,
  deepClone,
  isEmpty,
  get,
  set,
  unique,
  groupBy,
  sortBy,
  storage,
  url,
  validate,
  file,
  color,
}; 